/*
 Trabajo Practico 3 Ejercicio 1
 Entrega número: 1

 - Integrantes:
	- Martinez, Guillermo	DNI: 34510461
	- Barrera, Lourdes		DNI: 33306634
	- Reyes, Leandro		DNI: 34213699
	- Rodriguez, Lucas		DNI: 34265017
*/

#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <stdio.h>
#include <sys/select.h>
#include <unistd.h>
#include <termios.h>


#define NB_ENABLE 0
#define NB_DISABLE 1

void CreaSemaforos();
void CerrarSemaforos();
void EventoTeclado();

void nonblock(int);

int kbhit();
int Salir=0;

sem_t *MutexCaja = NULL, *MutexTramiteFinalizado = NULL, *HayClientes = NULL, *HayVips = NULL,
*PasaComunes = NULL,*PasaVips = NULL, *BancoAbierto = NULL;


char _MutexCaja[] = "SMutexCaja";
char _MutexTramiteFinalizado [] = "SMutexTramiteFinalizado";
char _HayClientes [] = "SHayClientes";
char _HayVips [] = "SHayVIps";
char _PasaComunes [] = "SPasaComunes";
char _PasaVips [] = "SPasaVips";
char _BancoAbierto [] = "SBancoAbierto";

void main(int argc, char *argv[])
{
	int j;
	int val;
	
	for(j=1;j<32;j++)
    {
        if(j!= 9  && j != 19)
            signal(j, SIG_IGN);
    }

	
	printf("Atención %d > Iniciando... Para finalizar presione S/s \n ", getpid());
	CreaSemaforos();
	
	nonblock(NB_ENABLE);

	sem_getvalue(HayClientes, &val);

	while((!Salir) || val != 0)
	{
		
		if(!sem_trywait(HayClientes))
		{
			if(!sem_trywait(HayVips))
			{
				printf("Atención %d > Atendiendo cliente VIP\n", getpid());
				sem_post(PasaVips);
			}
			else
			{
				printf("Atención %d > Atendiendo cliente Comun\n", getpid());
				sem_post(PasaComunes);
			}

			sem_getvalue(HayClientes, &val);

			while(sem_trywait(MutexTramiteFinalizado))
			{
				EventoTeclado();

				sem_getvalue(HayClientes, &val);
			}
		}
		
		EventoTeclado();

	}
	nonblock(NB_DISABLE);

	CerrarSemaforos();			
 
}


void EventoTeclado()
{
	char c; 
	if (!Salir && kbhit()!=0)
	{
		c=fgetc(stdin);
		if (c =='S' || c == 's')
		{
			Salir=1;
			sem_wait(BancoAbierto);	
		}
	}
	else
		usleep(1000);		

}

void CreaSemaforos()
{
	if((MutexCaja = sem_open(_MutexCaja,O_CREAT | O_EXCL ,0666,1)) == SEM_FAILED)
		goto Error;
		
	if((MutexTramiteFinalizado = sem_open(_MutexTramiteFinalizado,O_CREAT | O_EXCL,0666,0)) == SEM_FAILED) 
		goto Error;
		
	if((HayClientes = sem_open(_HayClientes,O_CREAT | O_EXCL,0666,0)) == SEM_FAILED) 
		goto Error;
		
	if((HayVips = sem_open(_HayVips,O_CREAT | O_EXCL,0666,0)) == SEM_FAILED)
		goto Error;		
	
	if((PasaComunes = sem_open(_PasaComunes,O_CREAT | O_EXCL,0666,0)) == SEM_FAILED)
		goto Error;
		
	if((PasaVips = sem_open(_PasaVips,O_CREAT | O_EXCL,0666,0)) == SEM_FAILED) 
		goto Error;

	if((BancoAbierto = sem_open(_BancoAbierto,O_CREAT | O_EXCL ,0666,1)) == SEM_FAILED)
		goto Error;
		
	return;
	
Error:
	printf("Error al crear semaforos \n");
	CerrarSemaforos();
	exit(-1);
}

void CerrarSemaforos()
{
	if(MutexCaja)
	{
		sem_close(MutexCaja);
		sem_unlink(_MutexCaja);
	}
	
	if(MutexTramiteFinalizado)
	{
		sem_close(MutexTramiteFinalizado);
		sem_unlink(_MutexTramiteFinalizado);
	}
	
	if(HayClientes)
	{
		sem_close(HayClientes);
		sem_unlink(_HayClientes);
	}
	
	if(HayVips)
	{	
		sem_close(HayVips);
		sem_unlink(_HayVips);
	}
	
	if(PasaComunes)
	{	
		sem_close(PasaComunes);
		sem_unlink(_PasaComunes);
	}

	if(BancoAbierto)
	{	
		sem_close(BancoAbierto);
		sem_unlink(_BancoAbierto);
	}

	if(PasaVips)
	{	
		sem_close(PasaVips);
		sem_unlink(_PasaVips);
	}
}
	
int kbhit()
{
    struct timeval tv;
    fd_set fds;
    tv.tv_sec = 0;
    tv.tv_usec = 0;
    FD_ZERO(&fds);
    FD_SET(STDIN_FILENO, &fds); //STDIN_FILENO is 0
    select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
    return FD_ISSET(STDIN_FILENO, &fds);
 }


void nonblock(int state)
{
    struct termios ttystate;
 
    //get the terminal state
    tcgetattr(STDIN_FILENO, &ttystate);
 
    if (state==NB_ENABLE)
    {
        //turn off canonical mode
        ttystate.c_lflag &= ~ICANON;
        //minimum of number input read.
        ttystate.c_cc[VMIN] = 1;
    }
    else if (state==NB_DISABLE)
    {
        //turn on canonical mode
        ttystate.c_lflag |= ICANON;
    }
    //set the terminal attributes.
    tcsetattr(STDIN_FILENO, TCSANOW, &ttystate); 
}

